﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GalaSoft.MvvmLight.Command;
using ZOIL.DataModel;
using System.Windows.Input;
using System.Windows;
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Threading;
using Db4objects.Db4o.Events;
using System.Collections.ObjectModel;
using Db4objects.Db4o;
using Db4objects.Db4o.Query;

namespace ZOIL.DataBackend.Server
{
    [ViewModelFor(typeof(DatabaseConfigurationListBoxView))]
    public class DatabaseConfigurationViewModel : BaseViewModel, IEditableObject
    {
        #region commands

        public RelayCommand<RoutedEventArgs> EditDatabaseNameCommand { get; private set; }
        public RelayCommand CancelledEditDatabaseNameCommand { get; private set; }
        public RelayCommand StartDatabaseCommand { get; private set; }
        public RelayCommand StopDatabaseCommand { get; private set; }
        public RelayCommand AddUserCommand { get; private set; }
        public RelayCommand ClearDatabaseCommand { get; private set; }


        #endregion

        #region constructor

        public DatabaseConfigurationViewModel()
        {
            EditDatabaseNameCommand = new RelayCommand<RoutedEventArgs>(OnEditDatabaseName);

            CancelledEditDatabaseNameCommand = new RelayCommand(OnCancelledEditDatabaseName);

            StartDatabaseCommand = new RelayCommand(OnStartDatabase);

            StopDatabaseCommand = new RelayCommand(OnStopDatabase);

            AddUserCommand = new RelayCommand(OnAddUser);

            ClearDatabaseCommand = new RelayCommand(OnClearDatabase);
        }

        #endregion

        #region public properties

        public String Name
        {
            get
            {
                return (Model as DatabaseConfiguration).Name;
            }
            set
            {
                (Model as DatabaseConfiguration).Name = value;
                RaisePropertyChanged("Name");
            }
        }

        public int Port
        {
            get
            {
                return (Model as DatabaseConfiguration).Port;
            }
            set
            {
                (Model as DatabaseConfiguration).Port = value;
                RaisePropertyChanged("Port");
            }
        }

        public String DatabaseFile
        {
            get
            {
                return (Model as DatabaseConfiguration).DatabaseFile;
            }
            set
            {
                (Model as DatabaseConfiguration).DatabaseFile = value;
                RaisePropertyChanged("DatabaseFile");
            }
        }

        public String Description
        {
            get
            {
                return (Model as DatabaseConfiguration).Description;
            }
            set
            {
                (Model as DatabaseConfiguration).Description = value;
                RaisePropertyChanged("Description");
            }
        }

        public DatabaseStatus Status
        {
            get
            {
                return (Model as DatabaseConfiguration).Status;
            }
            set
            {
                (Model as DatabaseConfiguration).Status = value;
                RaisePropertyChanged("Status");
            }
        }

        public ObservableCollection<DatabaseUser> Users
        {
            get
            {
                return (Model as DatabaseConfiguration).Users;
            }
        }

        private String _logText;
        public String LogText
        {
            get
            {
                return _logText;
            }
            set
            {
                _logText = value;
                RaisePropertyChanged("LogText");
            }
        }

        public bool UseMemoryIOAdapter
        {
            get
            {
                return (Model as DatabaseConfiguration).UseMemoryIOAdapter;
            }
            set
            {
                (Model as DatabaseConfiguration).UseMemoryIOAdapter = value;
                RaisePropertyChanged("UseMemoryIOAdapter");
            }
        }

        #endregion

        #region commands

        #region stop database command

        void OnStopDatabase()
        {
            DatabaseConfiguration config = Model as DatabaseConfiguration;
            if (config != null)
            {
                removeEventRegistryHandlers(config.Server.EventRegistry);
                config.Server.Stop();
                Status = DatabaseStatus.Stopped;
            }
        }

        #endregion

        #region start database command

        void OnStartDatabase()
        {
            DatabaseConfiguration config = Model as DatabaseConfiguration;
            if (config != null)
            {
                config.Server.EventRegistryAssigned += new EventHandler(Server_EventRegistryAssigned);
                config.Server.Start(config);
                Status = DatabaseStatus.Running;
            }
        }

        void Server_EventRegistryAssigned(object sender, EventArgs e)
        {
            DB4OServer s = (DB4OServer)sender;
            addEventRegistryHandlers(s.EventRegistry);
        }

        #endregion

        #region add user command

        void OnAddUser()
        {
            (Model as DatabaseConfiguration).Users.Add( new DatabaseUser("ztv","ztv"));
        }

        #endregion

        #region clear database command

        void OnClearDatabase()
        {
            IObjectContainer container = (Model as DatabaseConfiguration).Server.Objects;

            IQuery q = container.Query();

            IObjectSet result  = q.Execute();

            long[] ids = result.Ext().GetIDs();

            foreach(long id in ids)
            {
                object o = container.Ext().GetByID(id);
                container.Delete(o);
            }
            container.Commit();
        }

        #endregion

        #region edit database name command

        void OnEditDatabaseName(RoutedEventArgs e)
        {
            // invoke focus update at loaded priority so that template swap has time to complete
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Loaded, (ThreadStart)delegate()
            {
                UIElement container = e.Source as UIElement;
                if (container != null)
                {
                    container.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
                }
            });


            BeginEdit();
        }

        #endregion

        #region cancel edit database name command

        void OnCancelledEditDatabaseName()
        {
            CancelEdit();
            IsInEditMode = false;
        }

        #endregion

        #endregion

        #region Database Events

        private void addEventRegistryHandlers(IEventRegistry EventRegistry)
        {
            //EventRegistry.Activated += new ObjectEventHandler(EventRegistry_Activated);
            //EventRegistry.Activating += new CancellableObjectEventHandler(EventRegistry_Activating);
            //EventRegistry.ClassRegistered += new ClassEventHandler(EventRegistry_ClassRegistered);
            //EventRegistry.Closing += new ObjectContainerEventHandler(EventRegistry_Closing);
            //EventRegistry.Committed += new CommitEventHandler(EventRegistry_Committed);
            //EventRegistry.Committing += new CommitEventHandler(EventRegistry_Committing);
            //EventRegistry.Created += new ObjectEventHandler(EventRegistry_Created);
            //EventRegistry.Creating += new CancellableObjectEventHandler(EventRegistry_Creating);
            //EventRegistry.Deactivated += new ObjectEventHandler(EventRegistry_Deactivated);
            //EventRegistry.Deactivating += new CancellableObjectEventHandler(EventRegistry_Deactivating);
            //EventRegistry.Deleted += new ObjectEventHandler(EventRegistry_Deleted);
            //EventRegistry.Deleting += new CancellableObjectEventHandler(EventRegistry_Deleting);
            //EventRegistry.Instantiated += new ObjectEventHandler(EventRegistry_Instantiated);
            //EventRegistry.QueryFinished += new QueryEventHandler(EventRegistry_QueryFinished);
            //EventRegistry.QueryStarted += new QueryEventHandler(EventRegistry_QueryStarted);
            //EventRegistry.Updated += new ObjectEventHandler(EventRegistry_Updated);
            //EventRegistry.Updating += new CancellableObjectEventHandler(EventRegistry_Updating);
        }

        private void removeEventRegistryHandlers(IEventRegistry EventRegistry)
        {
            //EventRegistry.Activated -= EventRegistry_Activated;
            //EventRegistry.Activating -= EventRegistry_Activating;
            //EventRegistry.ClassRegistered -= EventRegistry_ClassRegistered;
            //EventRegistry.Closing -= EventRegistry_Closing;
            //EventRegistry.Committed -= EventRegistry_Committed;
            //EventRegistry.Committing -= EventRegistry_Committing;
            //EventRegistry.Created -= EventRegistry_Created;
            //EventRegistry.Creating -= EventRegistry_Creating;
            //EventRegistry.Deactivated -= EventRegistry_Deactivated;
            //EventRegistry.Deactivating -= EventRegistry_Deactivating;
            //EventRegistry.Deleted -= EventRegistry_Deleted;
            //EventRegistry.Deleting -= EventRegistry_Deleting;
            //EventRegistry.Instantiated -= EventRegistry_Instantiated;
            //EventRegistry.QueryFinished -= EventRegistry_QueryFinished;
            //EventRegistry.QueryStarted -= EventRegistry_QueryStarted;
            //EventRegistry.Updated -= EventRegistry_Updated;
            //EventRegistry.Updating -= EventRegistry_Updating;
        }

        void EventRegistry_Updating(object sender, CancellableObjectEventArgs args)
        {
            throw new NotImplementedException();
        }

        void EventRegistry_Updated(object sender, ObjectEventArgs args)
        {
            throw new NotImplementedException();
        }

        void EventRegistry_QueryStarted(object sender, QueryEventArgs args)
        {
            throw new NotImplementedException();
        }

        void EventRegistry_QueryFinished(object sender, QueryEventArgs args)
        {
            throw new NotImplementedException();
        }

        void EventRegistry_Instantiated(object sender, ObjectEventArgs args)
        {
            LogText += "\nInstantiated Object of type: " + args.Object.GetType();
        }

        void EventRegistry_Deleting(object sender, CancellableObjectEventArgs args)
        {
            throw new NotImplementedException();
        }

        void EventRegistry_Deleted(object sender, ObjectEventArgs args)
        {
            throw new NotImplementedException();
        }

        void EventRegistry_Deactivating(object sender, CancellableObjectEventArgs args)
        {
            throw new NotImplementedException();
        }

        void EventRegistry_Deactivated(object sender, ObjectEventArgs args)
        {
            throw new NotImplementedException();
        }

        void EventRegistry_Creating(object sender, CancellableObjectEventArgs args)
        {
            throw new NotImplementedException();
        }

        void EventRegistry_Created(object sender, ObjectEventArgs args)
        {
            throw new NotImplementedException();
        }

        void EventRegistry_Committing(object sender, CommitEventArgs args)
        {
            LogText +=  "\nAbout to commit changes";
        }

        void EventRegistry_Committed(object sender, CommitEventArgs args)
        {
            LogText += "\nCommitted changes";
        }

        void EventRegistry_Closing(object sender, ObjectContainerEventArgs args)
        {
            LogText += "\nClosing Database";
        }

        void EventRegistry_ClassRegistered(object sender, ClassEventArgs args)
        {
            LogText += "\nNew Class '" + sender.ToString() +"' got registered";
        }

        void EventRegistry_Activating(object sender, CancellableObjectEventArgs args)
        {
            LogText += "\nActivating object of type: " + args.Object.GetType();
        }

        void EventRegistry_Activated(object sender, ObjectEventArgs args)
        {
            LogText += "\nObject of type: " + args.Object.GetType() + " got activated";
        }

        #endregion

        #region IEditableObject Members

        public void BeginEdit()
        {
            IsInEditMode = true;
        }

        public void CancelEdit()
        {
            IsInEditMode = false;
        }

        public void EndEdit()
        {
            IsInEditMode = false;
        }

        private bool _isInEditMode = false;
        public bool IsInEditMode
        {
            get { return _isInEditMode; }
            private set
            {
                if (_isInEditMode != value)
                {
                    _isInEditMode = value;
                    RaisePropertyChanged("IsInEditMode");
                }
            }
        }

        #endregion
    }
}
